filter
是傳入一個會回傳 Bool
的 function 及 List,然後將 List 中每個元素丟進去 function 最後回傳所有執行該 function 後為 True
的元素。
:t filter --filter :: (a -> Bool) -> [a] -> [a]
filter (>8) [1..10] -- [9,10]
filter (`elem` ['a'..'c']) ['a'..'e'] -- "abc"
其實使用起來跟 map
有八成像,都是傳入 function 及 List。
稍微敏銳的讀者應該會發現其實上面的行為我用 List comprehension 也是能夠做到一樣的事情的
其實
map
也是能用 List comprehension 做到一樣的事哦
[x| x <- [1..10] , x >8 ]
[x| x <- ['a'..'e'] , x `elem` ['a'..'c']]
那至於什麼時候要用 List comprehension 什麼時候要用 filter
或者 map
,我覺得就看個人喜好以及用哪種方式寫起來比較順手了,在多重限制條件下可能用 List comprehension 會比 filter
、map
較為易讀吧。
說回 filter
及 map
,他們應該也是 FP 中最常用到的function 了通常我們會同時用 map
與 filter
的各種組合技來將我們想要的資料給變出來。
像是
squareEven :: [Int] -> [Int]
squareEven xs =
map (^2) (filter even xs)
squareRootOfPositives :: [Double] -> [Double]
squareRootOfPositives xs =
map sqrt (filter (> 0) xs)
squareEven
是先將偶數取出來後再經過 map
讓每個數都取平方
squareRootOfPositives
則是講將大於 0
的數值取出來後再開根號
大多數時候我們
lamda 就是匿名函數,最常用在 higher order function 上,有時候要傳入的 function 邏輯可能非常複雜,但又不想為此額外宣告一個 function 那我們就會用 lamda 來幫助我們。
使用上只要加一個 \
就好了。
filter (\ x -> x `mod` 3 == 0 || x `mod` 7 == 0) [1..30]
-- [3,6,7,9,12,14,15,18,21,24,27,28,30]
這邊 (\ x -> ...)
的 x
就是從 List 丟進去 lamda 的元素。
既然 lamda 像是一種 function 那我們當然可以繼續應用之前所說的特性像是 pattern matching,只是無法設置多個條件,所以其實是有機會發生 runtime error
map (\(x:xs) -> 2*x + sum xs) [[1..5],[5..10],[11,15]] -- [16,50,37]
我們可以藉此匹配到二維 List 中每個 List 的 第一個元素及剩下的元素並將第一個元素乘2後與剩下元素的加總相加。
也因為 curried function 的關係其實以下這兩種寫法是等價的
add:: Num a => a -> a -> a
add x y = x + y
add' :: Num a => a -> a -> a
add' = \x -> \y -> x + y
add'
剛好也很適合解釋 Num a => a -> a -> a
這個 type ,將第一次傳入的參數放進第一個 lamda 然後將第二次傳入的參數放進第二個 lamda
寫到現在相信讀者能夠開始體會到 FP 的好玩之處,會發現我們大多數時候是在想「資料要變什麼樣」而不是「要怎麼讓資料變成那樣」。
今天的程式碼
https://github.com/toddLiao469469/30days-for-haskell